//封装锁

#include <iostream>
#include <unistd.h>
#include <vector>
#include "thread.hpp"
#include "LockGuard.hpp"

string GetThreadName()
{
    static int number = 1;
    char name[64];
    snprintf(name, sizeof(name), "Thread-%d", number++);
    return name;
}

int ticket = 10000;                                // 全局的共享资源

//传递线程对象(线程名+互斥锁)
class ThreadData
{
public:
    ThreadData(const string& name, pthread_mutex_t* lock)
    :threadname(name)
    ,pmutex(lock)
    {}
public:    
    string threadname;
    pthread_mutex_t* pmutex;
};

void GetTicket(ThreadData* td)
{
    while (true)
    {
        LockGuard lockguard(td->pmutex); //定义临时守护锁对象
        { //代码块明确表明是临界区
            if (ticket > 0)
            {
                // 充当抢票花费的时间
                usleep(1000);
                printf("%s get a ticket : %d\n", td->threadname.c_str(), ticket);
                ticket--;
            }
            else
            {
                break;
            }
        }
        // 实际情况, 还有后续的动作
    }
}

int main()
{
    //定义锁并初始化锁
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, nullptr);;

    string name1 = GetThreadName();
    ThreadData* td1 = new ThreadData(name1, &mutex);
    Thread<ThreadData*> t1(name1, GetTicket, td1);

    string name2 = GetThreadName();
    ThreadData* td2 = new ThreadData(name2, &mutex);
    Thread<ThreadData*> t2(name2, GetTicket, td2);

    string name3 = GetThreadName();
    ThreadData* td3 = new ThreadData(name3, &mutex);
    Thread<ThreadData*> t3(name3, GetTicket, td3);

    string name4 = GetThreadName();
    ThreadData* td4 = new ThreadData(name4, &mutex);
    Thread<ThreadData*> t4(name4, GetTicket, td4);

    t1.start();
    t2.start();
    t3.start();
    t4.start();

    t1.join();
    t2.join();
    t3.join();
    t4.join();

    delete td1;
    delete td2;
    delete td3;
    delete td4;

    pthread_mutex_destroy(&mutex);
    return 0;
}


//个别系统中, 抢票代码会出现很多的票被同一个线程抢完了
//多线程运行, 同一份资源，有线程长时间无法拥有，饥饿问题
//要解决饥饿问题，要让线程执行的时候，保持一定的顺序性 --- 同步

//线程加锁的本质:
//大多数体系结构都提供了swap和exchange指令, 作用是把寄存器内容和内存单元的数据进行交换
//exchange eax mem_addr, 就一条汇编语句，因此是原子的
//锁的本质: 
// struct 
// {
//     int mutex;
// };
//汇编画图理解加锁和解锁的原子性

//加锁的原则, 一般原则是谁加锁，谁解锁!

//可重入 vs 线程安全 
//重入/不可重入描述的是函数的特点, 和线程没有任何关系 --- 绝大部分函数是不可重入的!!!
//线程安全: 描述的是线程的特征
//线程不安全的情况

//死锁问题
